/*
 * Albareth - an action roleplaying game.
 * Copyright (C) 2008 Jens Anuth
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 *   02110-1301, USA.
 * 
 * $Id: Location.java 45 2008-05-14 23:04:29Z jens464 $
*/
package albareth.util;

import java.util.LinkedList;
import java.util.List;

import albareth.core.GameMap;
import albareth.core.World;
import albareth.core.entity.Ground;
import albareth.core.entity.GroundType;
import albareth.core.entity.Mobile;
import frosch.util.Coordinates;
import frosch.util.Direction;


/**
 * A location in the game. (x|y|z|map).
 * TODO: derive from frosch.util.Coordinates.
 */
public class Location implements Cloneable
{
    public int x, y;
    public GameMap map = null;


    public Location(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    public Location(int x, int y, GameMap m)
    {
        this(x, y);
        map = m;
    }
    
    public Location(Location location)
    {
        this(location.x, location.y, location.map);
    }
    
    public int getX() {
        return x;
    }
    
    public int getY() {
        return y;
    }
    
    public Coordinates getCoordinates()
    {
        return new Coordinates(x, y);
    }
    
    public GameMap getMap()
    {
        return map;
    }

    public World getWorld()
    {
        return map.getWorld();
    }

    public Ground getGround()
    {
        if (map == null) {
            return null;
        } else {
            return map.getGround(x, y);
        }
    }

    public GroundType getGroundType()
    {
        if (map == null) {
            return null;
        } else {
            return map.getGroundType(x, y);
        }
    }

    public List getItems()
    {
        if (map == null) {
            return null;
        } else {
            return map.getItems(x, y);
        }
    }

    public Mobile getMobile()
    {
        if (map == null) {
            return null;
        } else {
            return map.getMobile(x, y);
        }
    }
    
    public boolean isBlocked()
    {
        return map.isBlocked(x, y);
    }

    public int distance(Location loc2)
    {
        if (getMap() != loc2.getMap()) {
            return Integer.MAX_VALUE;
        } else {
            return (int)Coordinates.euclideanDistance(x, y, loc2.x, loc2.y);
        }
    }

    public String toString()
    {
        return "(" + getX() + ", " + getY() + ", " + map + ")";
    }

    /**
     * Gets the neighbor location in the given direction.
     */
    public Location getNeighborLocation(int direction)
    {
        int x = getX();
        int y = getY();
        if ((direction & Direction.NORTH) > 0) y--;
        if ((direction & Direction.SOUTH) > 0) y++;
        if ((direction & Direction.WEST) > 0) x--;
        if ((direction & Direction.EAST) > 0) x++;
        Location loc = new Location(x, y, map);
        return loc;
    }

    public List getAllNeighborLocations()
    {
        List neighbors = new LinkedList();
        neighbors.add(getNeighborLocation(Direction.NORTH));
        neighbors.add(getNeighborLocation(Direction.SOUTH));
        neighbors.add(getNeighborLocation(Direction.EAST));
        neighbors.add(getNeighborLocation(Direction.WEST));
        neighbors.add(getNeighborLocation(Direction.NORTH|Direction.WEST));
        neighbors.add(getNeighborLocation(Direction.NORTH|Direction.EAST));
        neighbors.add(getNeighborLocation(Direction.SOUTH|Direction.WEST));
        neighbors.add(getNeighborLocation(Direction.SOUTH|Direction.EAST));
        return neighbors;
    }

    public boolean equals(Object obj)
    {
        //instanceof check omitted for speed.
        Location other = (Location)obj;
        return x == other.x && y == other.y && map == other.map;
    }

    public boolean inflictDamage(int rawDamage, int damageType, Mobile causer)
    {
        if (getMap() != null) {
            return getMap().damageOnCell(x, y, rawDamage, damageType, causer);
        }
        return false;
    }
    
    
    
}
